package com.investmenttechnologyservices.services;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.inject.Inject;
import com.investmenttechnologyservices.datadictionary.FieldType;
import com.investmenttechnologyservices.model.Account;

public class AccountServiceImpl implements AccountService {
	
	private static final String ACCOUNT = "account";
	private static final String ACCOUNT_PICKER = "accountPicker";
	
	private DatastoreService ds;
	private DatastoreHelper datastoreHelper;
	private LoginService loginService;
	private UserService userService;
	
	@Inject
	AccountServiceImpl(DatastoreService ds, DatastoreHelper datastoreHelper, 
			LoginService loginService, UserService userService) {
		this.ds = ds;
		this.datastoreHelper = datastoreHelper;
		this.loginService = loginService;
		this.userService = userService;
	}
	
	@Override
	public void create(HttpServletRequest req, HttpServletResponse res) throws Exception {
		Key firmKey = loginService.getFirmKeyForCurrentUser();
		checkNotNull(firmKey, "Firm not found.");
		String name = req.getParameter("name");
		checkNotNull(name, "Account name cannot be null.");
		@SuppressWarnings("unchecked")
		List<String> defaultTagsList = (List<String>) FieldType.ARRAYSTR.stringToValue(req.getParameter("defaultTags"));
		Set<String> defaultTagSet = defaultTagsList == null ? null : new HashSet<String>(defaultTagsList);
		Account account = new Account(firmKey, name, defaultTagSet);
		ds.put(account.asEntity());
		datastoreHelper.writeEntity(res.getWriter(), ACCOUNT, account.asEntity());
	}

	@Override
	public void findAll(HttpServletRequest req, HttpServletResponse res) throws Exception {
		Key firmKey = loginService.getFirmKeyForCurrentUser();
		checkNotNull(firmKey, "Firm not found.");
		List<Entity> accounts = ds.prepare(
				new Query(ACCOUNT).setAncestor(firmKey)).asList(
				FetchOptions.Builder.withDefaults());
		datastoreHelper.writeEntities(res.getWriter(), ACCOUNT, accounts);
	}

	@Override
	public void pickerFindAll(HttpServletRequest req, HttpServletResponse res) throws Exception {
		datastoreHelper.findAll(ACCOUNT_PICKER, req, res);
	}
	
	@Override
	public Date getAccountLastLoadedDate(Key accountKey) {
		Date lastLoadDate = null;
		try {
			Account account = new Account(ds.get(accountKey));
			lastLoadDate = account.getLastLoadedDate();
		} catch (EntityNotFoundException ex) {
			// TODO Auto-generated catch block
			ex.printStackTrace();
		}
		return lastLoadDate;
	}

	@Override
	public Date getAccountLastLoadedDate() {
		return null;
	}

	@Override
	public Iterable<Entity> getAccountListByFirm(Key firmKey, boolean keysOnly) {
		Query accountQuery = new Query(ACCOUNT).setAncestor(firmKey);
		if (keysOnly) {
			accountQuery.setKeysOnly();
		}
		return ds.prepare(accountQuery).asIterable();
	}

	@Override
	public Boolean checkUserAndAccount(Key accountKey) {
		Boolean userOk = false;
		
		User user = userService.getCurrentUser();
		checkNotNull(user, "User is not logged in.");

		Key firmKey = loginService.getFirmKeyForCurrentUser();
		checkNotNull(firmKey, "User's firm not found!");
		
		if (accountKey == null)
			userOk = true;
		else {
			Iterable<Entity> accounts = getAccountListByFirm(firmKey, true);
			Iterator<Entity> iter = accounts.iterator();

			// get the accountKey for the Trade and compare to the accounts for the user's firm
			while (iter.hasNext() && !userOk) {
				Key key = iter.next().getKey();
				if (key.equals(accountKey))
					userOk = true;
			}
		}
		return userOk;
	}

}
